<?php
/**
 *
 *  Exchange (via IMAP)
 *
 *  Exchange (via IMAP) interaction
 *
 *  @author     David Lasley, dave -at- dlasley -dot- net
 *  @package    pyhp-imap
 *  @version    $Id: class.exchange.php 2 2012-12-12 19:35:18Z dave@dlasley.net $
 *  
 **/
/*
 *  Exchange Class
 */
class exchange{
    /*
     *  @param  string  $username   Exhchange uname
     *  @param  string  $password   Exhchange pass
     *  @param  string  $inbox      Inbox
     *  @param  string  $alias      Box alias
     *  @param  string  $domain     Domain
     *  @param  string  $server     Server address
     *
     *  @return bool
     */
    public function __construct($username, $password, $inbox='INBOX', $alias = '', $domain='COMPANY', $server='exchange.company.com'){
        
        if(!is_resource($this->inbox)){
            
            if($alias !== '')
                $alias = "/$alias";
            
            if($domain !== '')
                $domain = $domain."/";
            
            $username = $domain.$username.$alias;
            
            $tryCnt = 0;
            
            while(!is_resource($this->inbox)){
                
                $this->inbox = imap_open("{".$server.":993/imap/ssl/novalidate-cert}$inbox", $username, $password, NULL, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'));
                $tryCnt ++;
                
                if(!is_resource($this->inbox)){
                    
                    $this->inbox = imap_open("{".$server.":993/imap/ssl/novalidate-cert}$inbox", $username, $password, NULL, 1, array('DISABLE_AUTHENTICATOR' => 'PLAIN'));
                    $tryCnt ++;
                    
                }
                
                if($tryCnt > 20){
                    
                    echo "Cannot Connect To Exchange Server:<BR>";
                    die(var_dump(imap_errors()));
                    
                }
                
            }

            return true;
            
        }
        
    }
    
    /*
     *  Close connection
     *
     *  @return bool
     */
    public function __destruct(){
        
        imap_close($this->inbox,CL_EXPUNGE);
        return true;
        
    }
    /*
     *  Movie email to folder
     *
     *  @param  string  $uid    message UID
     *  @param  string  $moveTo folder to move to
     *
     *  @return bool  
     */
    public function moveEmail($uid, $moveTo){
        
        //Move email to defined mailbox
        imap_mail_move ($this->inbox, $uid, $moveTo, CP_UID);
        return true;

    }
    /*
     *  Delete email
     *
     *  @param  string  $uid    message UID
     *
     *  @return bool
     */
    public function deleteEmail($uid){
        
        //Delete Email
        imap_delete($this->inbox, $uid, FT_UID);
        return true;
        
    }
    /*
     *  Reply to email
     *
     *  @param  string  $msgnum Message UID
     *  @param  string  $body   Message Body
     *
     *  @todo Complete this
     */
    public function reply($msgnum, $body){
        
        $replyTxt = $this::parseEmail($msgnum);
        $replyTxt = preg_replace("%(/* Font Definitions */|/* Style Definitions */m)(.*?)-->%","",$replyTxt);
        
        
    }
    /*
     *  Check folder for emails
     *
     *  @param  string  $mBox                   Mailbox
     *  @param  bool    $readEmails             Read emails, or just grab headers?
     *  @param  bool    $reverseSort            Sort in reverse
     *  @param  bool    $downloadAttachments    DL atrtachments?
     *
     *  @return bool
     */
    public function checkEmails($mBox = "ALL", $readEmails = false, $reverseSort = false, $downloadAttachments=false){
        
        //Grab emails
        $emails = imap_search($this->inbox,$mBox);
        
        if($emails){
            $reverseSort = true;
            //Newest emails on top?
            if($reverseSort){
                
                rsort($emails);
                
            }
            
            $cnt = 0;
            
            //Loop emails
            foreach($emails as $email_number){
                
                if($readEmails){
                    
                    $body = $this::parseEmail($email_number,0,$downloadAttachments);
                    
                }
                
                foreach($body['savedFiles'] as $filepath=>$filename){
                    if(!empty($filename)){
                        $this->emails[$body['uuid']]->savedFiles->$filepath = $filename;
                    }
                }

                   /* preg_match_all("@<(.*?)>(.*)</(.*?)>@",$body,$matches);

                    preg_match_all("/boundary=\"(.*?)\"/", $body, $matches);
                    var_dump($matches);
                    var_dump(nl2br($body));
                    $body = str_replace($matches[0][0],'',$body);
                    $boundary = $matches[1][0];*/

                    //die(mb_detect_encoding ($body));
                    //preg_match_all('@Content-Transfer-Encoding: (.*?) Content-Type: (.*?); charset="(.*?)"@',$body,$stuff);

 /*                   $body = explode($boundary." ",$body);
                    $cnt=0;
                    foreach($body as $bodyPart){
                        //echo '%Content-Transfer-Encoding: (.*?) Content-Type: (.*?); charset=(.*?)%';
                        echo "<b>$cnt</b><br>$bodyPart<br>";
                        $cnt++;
                        
                    }*/

                    if($body["HTML"]['value'] !== ""){
                        
                        if(strpos(strtolower($body["HTML"]['value']), "<br>") !== false){

                            $out = $body["HTML"]['value'];
                            
                        }else{

                            $out = nl2br($body["HTML"]['value']);
                            
                        }

                    }else{

                        $out = nl2br($body["PLAIN"]['value']);
                        
                    }
                    
                    //$out = preg_replace("%/\* [a-zA-Z]{1,20} Definitions \*/(.*)-->%s", ' -->', $out);
                    //$out = preg_replace("%<!--(.*)-->%s", '', $out);
                    
                    //$out = preg_replace("~(?i)(<br>){2,}(?-i)~","<br>",$out);

                    $this->emails[$body['uuid']]->message = str_replace("\r\n",'',$out);
                    
                    foreach($body['header'] as $key=>$attribute){
                        
                        $this->emails[$body['uuid']]->$key = $attribute;
                        
                    }
                    
                    $this->emails[$body['uuid']]->headers = $body['headers']['value'];
                    
                    //die(var_dump($this->emails));
                    //If message was unread before script, clear \\Seen flag
                    if($this->emails[$body['uuid']]->seen == 0){
                    
                        imap_clearflag_full ( $this->inbox , $email_number, '\\Seen' );
                    
                    }

                $cnt++;
                
            }
            
        }

        $this->emailCount = $cnt;
        return true;
        
    }
    
    /*
     *  Parses an email
     *
     *  @param  string  $email_number           UID
     *  @param  string  $uid                    UID?
     *  @param  bool    $downloadAttachments    DL attachments
     */
    public function parseEmail($email_number, $uid = 0, $downloadAttachments=false){
        
            include_once(dirname(__FILE__) . "/sanitization.php");
            
                //Fetch email headers
                $overview = imap_fetch_overview($this->inbox,$email_number,$uid);
                //$this->emails[$overview[0]->uid] = $overview[0];
                $header = imap_fetchbody($this->inbox, $email_number,0,$uid);
                
                foreach($overview[0] as $key=>$single){
                    
                    $body['header'][$key] = $single;
                    
                }
                
                $body['headers']['value'] = imap_fetchheader($this->inbox, $email_number,$uid);

                //Read emails?
                //if($readEmails){
                    
                    // pull the plain text for message $n
                    $st = imap_fetchstructure($this->inbox, $email_number, $uid);

                    if (!empty($st->parts)) {
                        
                        for ($i = 0, $j = count($st->parts); $i < $j; $i++) {
                            
                            $part = $st->parts[$i];
                            
                            if(!empty($part->parts)){
                                
                                $cnt=0;
                                
                                foreach($part->parts as $single){
                                    
                                    switch($single->subtype){
                                        
                                        case 'HTML':
                                        case 'PLAIN':
                                            
                                            $body[$single->subtype]['value'] = imap_fetchbody($this->inbox, $email_number, $i+1 . '.' . $cnt, $uid);
                                            $body[$single->subtype]['encoding'] = $single->encoding;
                                            break;
                                        
                                    }
                                    
                                    foreach($single->parameters as $parameter){
                        
                                        switch($parameter->attribute){
                                            
                                            case 'boundary':
                                                $boundary = $parameter->value;
                                                break;
                                            case 'charset':
                                                $body['charset'] = $parameter->value;
                                            
                                        }
                
                                    }
                                    $cnt++;
                                    
                                }
                                
                            }else{
                                switch($part->subtype){
                                    
                                    case 'HTML':
                                    case 'PLAIN':
                                        $body[$part->subtype]['value'] = imap_fetchbody($this->inbox, $email_number, $i+1, $uid);
                                        $body[$part->subtype]['encoding'] = $part->encoding;
                                        /*foreach($this->extract_attachments($this->inbox,$email_number) as $attachment){
                                            if(!empty($attachment['filename'])){
                                                file_put_contents("/var/www/shared_data/temp/".$attachment['filename'],$attachment['attachment']);
                                                $body['savedFiles']["/var/www/shared_data/temp/".$attachment['filename']] = $attachment['filename'];
                                            }
                                        }*/
                                        break;
                                    case 'VND.MS-EXCEL':
                                    case 'VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET':
                                        //var_dump($this->extract_attachments($this->inbox,$email_number));
                                        break;
                                    case 'JPEG':
                                    case 'PNG':
                                        break;
                                    case 'X-GZIP':
                                    case 'OCTET-STREAM':
                                        /*foreach($this->extract_attachments($this->inbox,$email_number) as $attachment){
                                            if(!empty($attachment['filename'])){
                                                file_put_contents("/var/www/shared_data/temp/".$attachment['filename'],$attachment['attachment']);
                                                $body['savedFiles']["/var/www/shared_data/temp/".$attachment['filename']] = $attachment['filename'];
                                            }
                                        }*/
                                        break;
                                    default:
                                        echo "\r\n\r\n".$part->subtype."\r\n\r\n";
                                    
                                }
                                
                                foreach($part->parameters as $parameter){
                        
                                    switch($parameter->attribute){
                                        
                                        case 'boundary':
                                            $boundary = $parameter->value;
                                            break;
                                        case 'charset':
                                            $body['charset'] = $parameter->value;
                                        
                                    }
                
                                }
                                
                            }

                        }
                    } else {
                        
                        $body['HTML']['value'] = imap_body($this->inbox, $email_number, $uid);
                        $body['HTML']['encoding'] = $part->encoding;
                        
                        foreach($st->parameters as $parameter){
                        
                                        switch($parameter->attribute){
                                            
                                            case 'boundary':
                                                $boundary = $parameter->value;
                                                break;
                                            case 'charset':
                                                $body['charset'] = $parameter->value;
                                            
                                        }
                
                                    }
                        
                    }
                    
                    foreach($body as $key=>$single){
                        
                        switch($key){
                            
                            case 'charset':
                                
                                break;
                            default:
                                switch($single['encoding']){
                                    
                                    case 0:
                                        $body[$key]['value'] = $single['value'];
                                        break;
                                    case 1:
                                        $body[$key]['value'] = mb_convert_encoding(imap_8bit($single['value']),'us-ascii',$body['charset']);
                                        break;
                                    case 2:
                                        $body[$key]['value'] = mb_convert_encoding(imap_binary($single['value']),'us-ascii',$body['charset']);
                                        break;
                                    case 3:
                                        $body[$key]['value'] = mb_convert_encoding(imap_base64($single['value']),'us-ascii',$body['charset']);
                                        break;
                                    case 4:
                                        $body[$key]['value'] = mb_convert_encoding(quoted_printable_decode($single['value']),'us-ascii',$body['charset']);
                                        break;
                                    case 5:
                                        $body[$key]['value'] = mb_convert_encoding($single['value'],'us-ascii',$body['charset']);
                                        break;
                                    
                                }
                            
                        }
                        
                    }
                    
                    if($downloadAttachments == true){
                        
                        /*foreach($this->extract_attachments($this->inbox,$email_number) as $attachment){
                            if(!empty($attachment['filename'])){
                                file_put_contents("/var/www/shared_data/temp/".$attachment['filename'],$attachment['attachment']);
                                $body['savedFiles']["/var/www/shared_data/temp/".$attachment['filename']] = $attachment['filename'];
                            }
                        }*/
                        $body['savedFiles'] = $this->writeAttachmentsToDisk($this->inbox,$email_number);
                        
                    }
                    
                    $body['uuid'] = $overview[0]->uid;
                    
                    return $body;

    }
    /*
     *  Save attachments
     *
     *  @param  string  $mailbox    Mailbox
     *  @param  string  $msg_number UID
     *  @param  string  $dir        save dir
     *
     *  @return mixed   false if fail, otherwise array of output files
     */
    function writeAttachmentsToDisk($mailbox, $msg_number, $dir='/var/www/shared_data/temp/'){
      
      if (!file_exists($dir)){
        mkdir($dir);
      }
      $filename = "tmp.eml";
      $email_file = $dir."/".$filename;
      // write the message body to disk
      imap_savebody  ($mailbox, $email_file, $msg_number);
      $command = "munpack -C $dir -fq $email_file";
      // invoke munpack which will 
      // write all the attachments to $dir
      exec($command,$output);
    
      // if($output[0]!='Did not find anything to unpack from $filename') {
      $found_file = false;
      foreach ($output as $attach) {
        $pieces = explode(" ", $attach);
        $part = $pieces[0];
        if (file_exists($dir.$part)){
          $found_file = true;
          $files[] = $part;
        }
      }
      if (!$found_file){
        //echo ("\nMail.php : no files found - cleaning up. ");
        // didn't find any output files - delete the directory and email file
        unlink($email_file);
        rmdir($dir);
        return false;
      }
      else {
        // found some files-  just delete the email file
        unlink($email_file);
        return $files;
      }
    }
    
    /*
     *  Extract attachment from email
     *
     *  @param  object  $connection     Connection Object
     *  @param  string  $message_number UID
     *
     *  @return array   attachments
     */
    function extract_attachments($connection, $message_number) {
   
        $attachments = array();
        $structure = imap_fetchstructure($connection, $message_number);

        if(isset($structure->parts) && count($structure->parts)) {
       
            for($i = 0; $i < count($structure->parts); $i++) {
       
                $attachments[$i] = array(
                    'is_attachment' => false,
                    'filename' => '',
                    'name' => '',
                    'attachment' => ''
                );
               
                if($structure->parts[$i]->ifdparameters) {
                    foreach($structure->parts[$i]->dparameters as $object) {
                        if(strtolower($object->attribute) == 'filename') {
                            $attachments[$i]['is_attachment'] = true;
                            $attachments[$i]['filename'] = $object->value;
                        }
                    }
                }
               
                if($structure->parts[$i]->ifparameters) {
                    foreach($structure->parts[$i]->parameters as $object) {
                        if(strtolower($object->attribute) == 'name') {
                            $attachments[$i]['is_attachment'] = true;
                            $attachments[$i]['name'] = $object->value;
                        }
                    }
                }
               
                if($attachments[$i]['is_attachment']) {
                    $attachments[$i]['attachment'] = imap_fetchbody($connection, $message_number, $i+1);
                    if($structure->parts[$i]->encoding == 3) { // 3 = BASE64
                        $attachments[$i]['attachment'] = base64_decode($attachments[$i]['attachment']);
                    }
                    elseif($structure->parts[$i]->encoding == 4) { // 4 = QUOTED-PRINTABLE
                        $attachments[$i]['attachment'] = quoted_printable_decode($attachments[$i]['attachment']);
                    }
                }
               
            }
           
        }
       
        return $attachments;
       
    }
    /*
     *  Search AD
     *
     *  @param  string  $username   Bind Username
     *  @param  string  $pass       Bind Pass
     *  @param  string  $email      Look for
     *
     *  @return array   LDAP Entries
     */
    public function searchAD($username, $pass, $email){
        
        $pass = sanitizers::semiSecure($pass, true);
        
        // CONFIGURATION START
        $config = array		('host'     => 'NOCADC1.corp.company.com',  // FQDN of your domain controller
                                    'dn'    => 'DC=corp,DC=company,DC=com', 			   // Domain DN
                                'username'  => "$username@CORP.COMPANY.COM",		   // username with read access
                                'password'  => "$pass",					   // password for above
                                                );
        // $search_fields ,  select which AD fields you want to search on 
        $search_fields=array('Email' 		=> 'mail'   );
        
        //$return_fields , select which AD fields you wish to have displayed in the results
        $return_fields=array('Display Name' 	=> 'displayname',
                                'First Name' 	=> 'givenname', 
                                'Last Name' 	=> 'sn',
                            'Telephone Number' 	=> 'telephonenumber',
                            'Email Address' 	=> 'mail',
                            'Company' 		=> 'company',
                                'Account Name'  => 'samaccountname',
                                'Employee Type' => 'employeetype',
                                                 );
        $attrs=array();
        
         foreach ($return_fields as $item => $value) //build attr array
 	{
            $attrs[]=$value;
 	}

        $ldap_search = "(&(mail=$email))";
        
        $ad = ldap_connect($config['host'])
              or die( "Could not connect!" );
        
        // Set version number
        ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3)
             or die ("Could not set ldap protocol");
        ldap_set_option($ad, LDAP_OPT_REFERRALS,0)
                or die ("could not set the ldap referrals");
        
        // Binding to ldap server
        $bd = ldap_bind($ad, $config['username'], $config['password'])
              or die ("Could not bind");
        
        // Create the DN
        
        
        // Specify only those parameters we're interested in displaying
        
        
        // Create the filter from the search parameters
        $search = ldap_search($ad, $config['dn'], $ldap_search, $attrs)
                  or die ("ldap search failed");
        
        $entries = ldap_get_entries($ad, $search);

        return $entries;

    }

}

?>